package org.example.liuy.service.event;

import lombok.Getter;

import java.util.concurrent.ThreadLocalRandom;

/**
 * 投注事件类 - 使用不可变对象模式
 * <p>
 * 表示一个投注事件，包含所有相关信息。该类是不可变的，一旦创建就不能修改其状态。
 * </p>
 *
 * @author liuy
 * @since 1.0.0
 */
@Getter
public class StakeEvent {
    /**
     * 投注项ID
     */
    private final Integer betOfferId;

    /**
     * 客户ID
     */
    private final Integer customerId;

    /**
     * 当前投注金额
     */
    private final double stake;

    /**
     * 之前的投注金额
     */
    private final double previousStake;

    /**
     * 事件时间戳（毫秒）
     */
    private final long timestamp;

    /**
     * 事件唯一标识符
     */
    private final String eventId;

    /**
     * 构造一个新的投注事件
     *
     * @param betOfferId    投注项ID
     * @param customerId    客户ID
     * @param stake         当前投注金额
     * @param previousStake 之前的投注金额
     */
    public StakeEvent(Integer betOfferId, Integer customerId, double stake, double previousStake) {
        this.betOfferId = betOfferId;
        this.customerId = customerId;
        this.stake = stake;
        this.previousStake = previousStake;
        this.timestamp = System.currentTimeMillis();
        this.eventId = generateEventId();
    }

    /**
     * 建造者模式 - 用于创建投注事件
     * <p>
     * 提供一种更灵活的方式来构建StakeEvent对象，特别是当需要设置多个可选参数时
     * </p>
     */
    public static class Builder {
        private Integer betOfferId;
        private Integer customerId;
        private double stake;
        private double previousStake;

        /**
         * 设置投注项ID
         *
         * @param betOfferId 投注项ID
         * @return Builder实例
         */
        public Builder betOfferId(Integer betOfferId) {
            this.betOfferId = betOfferId;
            return this;
        }

        /**
         * 设置客户ID
         *
         * @param customerId 客户ID
         * @return Builder实例
         */
        public Builder customerId(Integer customerId) {
            this.customerId = customerId;
            return this;
        }

        /**
         * 设置当前投注金额
         *
         * @param stake 当前投注金额
         * @return Builder实例
         */
        public Builder stake(double stake) {
            this.stake = stake;
            return this;
        }

        /**
         * 设置之前的投注金额
         *
         * @param previousStake 之前的投注金额
         * @return Builder实例
         */
        public Builder previousStake(double previousStake) {
            this.previousStake = previousStake;
            return this;
        }

        /**
         * 构建StakeEvent对象
         *
         * @return 新的StakeEvent实例
         */
        public StakeEvent build() {
            return new StakeEvent(betOfferId, customerId, stake, previousStake);
        }
    }

    /**
     * 获取建造者实例
     *
     * @return 新的Builder实例
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * 判断是否为新投注（之前没有投注记录）
     *
     * @return 如果之前投注金额为0则返回true，否则返回false
     */
    public boolean isNewStake() {
        return previousStake == 0.0;
    }

    /**
     * 判断投注金额是否增加
     *
     * @return 如果当前投注金额大于之前投注金额则返回true，否则返回false
     */
    public boolean isStakeIncrease() {
        return stake > previousStake;
    }

    /**
     * 获取投注金额变化值
     *
     * @return 当前投注金额与之前投注金额的差值
     */
    public double getStakeChange() {
        return stake - previousStake;
    }

    /**
     * 生成唯一的事件ID
     * <p>
     * 格式为: event_时间戳_随机数
     * </p>
     *
     * @return 唯一的事件ID
     */
    private String generateEventId() {
        return "event_" + System.currentTimeMillis() + "_" +
                ThreadLocalRandom.current().nextInt(1000, 9999);
    }


    /**
     * 返回对象的字符串表示形式
     *
     * @return 包含所有关键信息的字符串
     */
    @Override
    public String toString() {
        return String.format("BettingEvent{eventId=%s, betOfferId=%s, customerId=%s, stake=%.2f, previousStake=%.2f, timestamp=%d}",
                eventId, betOfferId, customerId, stake, previousStake, timestamp);
    }

    /**
     * 转换为JSON格式（用于日志输出）
     *
     * @return JSON格式的字符串表示
     */
    public String toJson() {
        return String.format("{\"eventId\":\"%s\",\"betOfferId\":\"%s\",\"customerId\":\"%s\"," +
                        "\"stake\":%.2f,\"previousStake\":%.2f,\"timestamp\":%d,\"isNewStake\":%b,\"stakeChange\":%.2f}",
                eventId, betOfferId, customerId, stake, previousStake, timestamp, isNewStake(), getStakeChange());
    }

    /**
     * 转换为CSV格式
     *
     * @return CSV格式的字符串表示
     */
    public String toCsv() {
        return String.format("%s,%s,%s,%.2f,%.2f,%d,%b,%.2f",
                eventId, betOfferId, customerId, stake, previousStake, timestamp, isNewStake(), getStakeChange());
    }

    /**
     * 获取CSV头信息
     *
     * @return CSV格式的表头
     */
    public static String getCsvHeader() {
        return "eventId,betOfferId,customerId,stake,previousStake,timestamp,isNewStake,stakeChange";
    }
}
